#include "fv_inc.h"
#include "wxMainWindow.h"
#include "wxOpenGL.h"
#include "wxApproxModWnd.h"
#include "wxLegendDialog.h"
#include "wxScreenSettings.h"
#include "wxSolCalcDialog.h"
#include "wx/busyinfo.h"
#include "wx/image.h"
#include "wx/toolbar.h"
#include "wx/config.h"
//#include "wx/menu.h"
#include "wx/docview.h"
#include "fv_config.h"
#include "fv_exception.h"
#include "fv_txt_utls.h"
#include "BaseField.h"
#include "ViewManager.h"
#include "ModelControler.h"
#ifdef WIN32
#include "../win/resource.h"
#else
#include "../wx/resource.h"
#endif
#include "Log.h"

#include <sstream>
#include <algorithm>


// define this to use XPMs everywhere (by default, BMPs are used under Win)
// BMPs use less space, but aren't compiled into the executable on other platforms
#ifdef __WXMSW__
# define USE_XPM_BITMAPS 0
#else
# define USE_XPM_BITMAPS 1
#endif

#if USE_XPM_BITMAPS && defined(__WXMSW__) && !wxUSE_XPM_IN_MSW
# error You need to enable XPM support to use XPM bitmaps with toolbar!
#endif // USE_XPM_BITMAPS

// If this is 1, the sample will test an extra toolbar identical to the
// main one, but not managed by the frame. This can test subtle differences
// in the way toolbars are handled, especially on Mac where there is one
// native, 'installed' toolbar.
#define USE_UNMANAGED_TOOLBAR 0
#define MAX_HISTORY_FILES 	  8

// Define this as 0 for the platforms not supporting controls in toolbars
#define USE_CONTROLS_IN_TOOLBAR 1

// The toolbar
const int ID_TOOLBAR = 500;
static const long TOOLBAR_STYLE = wxTB_FLAT | wxTB_DOCKABLE | wxTB_TEXT;

// Resources
#if !defined(__WXMSW__) && !defined(__WXPM__)
    #include "../res/variable.xpm"
#endif

#if USE_XPM_BITMAPS
    #include "../res/xaxis.xpm"
    #include "../res/yaxis.xpm"
    #include "../res/zaxis.xpm"
    #include "../res/free.xpm"
#endif // USE_XPM_BITMAPS

enum {
	IDT_XDOF,IDT_YDOF,IDT_ZDOF,IDT_FDOF
};

namespace FemViewer {
namespace WxGUI		{

bool wxMainWindow::m_shutdown = false;

BEGIN_EVENT_TABLE(wxMainWindow, wxFrame)
	EVT_CHAR(wxMainWindow::OnChar)
	#ifndef _USE_FV_LIB
	EVT_MENU(IDM_FILE_OPENMESH,wxMainWindow::OnMenuFileOpen)
	EVT_MENU(IDM_FILE_OPENFIELD,wxMainWindow::OnMenuFileOpen)
	#endif
	EVT_MENU(IDM_FILE_REFRESH,wxMainWindow::OnMenuFileRefresh)
	EVT_MENU(IDM_FILE_RELOAD,wxMainWindow::OnMenuFileReload)
	EVT_MENU(IDM_FILE_CLEAR,wxMainWindow::OnMenuFileReset)
	#ifndef _USE_FV_LIB
	EVT_MENU_RANGE(wxID_FILE,wxID_FILE9, wxMainWindow::OnMenuFileHistory)
	#endif
	EVT_MENU(IDM_FILE_EXIT,wxMainWindow::OnMenuFileQuit)
	EVT_MENU(IDM_VIEW_PERSPECTIVE,wxMainWindow::OnMenuViewProjection)
	EVT_MENU(IDM_VIEW_ORTOGRAPHIC,wxMainWindow::OnMenuViewProjection)
	EVT_MENU(IDM_VIEW_TOP,wxMainWindow::OnMenuChangeView)
	EVT_MENU(IDM_VIEW_BOTTOM,wxMainWindow::OnMenuChangeView)
	EVT_MENU(IDM_VIEW_FRONT,wxMainWindow::OnMenuChangeView)
	EVT_MENU(IDM_VIEW_BACK,wxMainWindow::OnMenuChangeView)
	EVT_MENU(IDM_VIEW_LEFT,wxMainWindow::OnMenuChangeView)
	EVT_MENU(IDM_VIEW_RIGHT,wxMainWindow::OnMenuChangeView)
	EVT_MENU(IDM_VIEW_DEFAULT,wxMainWindow::OnMenuChangeView)
	EVT_MENU(IDM_VIEW_FULL,wxMainWindow::OnMenuViewMode)
	EVT_MENU(IDM_VIEW_BOUNDINGBOX,wxMainWindow::OnMenuViewMode)
	EVT_MENU(IDM_VIEW_FAST,wxMainWindow::OnMenuViewMode)
	EVT_MENU(IDM_VIEW_NEWVIEW,wxMainWindow::OnMenuViewNew)
	EVT_MENU(IDM_VIEW_NEXTVIEW,wxMainWindow::OnMenuViewNext)
	EVT_MENU(IDM_VIEW_PREVIOUSVIEW,wxMainWindow::OnMenuViewPrevious)
	EVT_MENU(IDM_VIEW_DUMPCURRENTVIEW,wxMainWindow::OnMenuViewDumpCurr)
	EVT_MENU(IDM_VIEW_DUMPALLVIEWS,wxMainWindow::OnMenuViewDumpAll)
	EVT_MENU(IDM_CONFIGURE_AXES,wxMainWindow::OnMenuConfigAxes)
	EVT_MENU(IDM_CONFIGURE_GRID,wxMainWindow::OnMenuConfigGrid)
	EVT_MENU(IDM_CONFIGURE_BACKGROUNDCOLOR, wxMainWindow::OnMenuConfigBkgColor)
	EVT_MENU(IDM_CONFIGURE_LIGHT,wxMainWindow::OnMenuConfigLight)
	EVT_MENU(IDM_CONFIGURE_RESET,wxMainWindow::OnMenuConfigReset)
	EVT_MENU(IDM_CONFIGURE_SAVECONFIGURATION,wxMainWindow::OnMenuConfigSave)
	EVT_MENU(IDM_CONFIGURE_EDITLEGEND,wxMainWindow::OnMenuConfigLegendEdit)
	EVT_MENU(IDM_CONFIGURE_CHANGEAPROXIMATIONMODULE,wxMainWindow::OnMenuConfigModuleApprox)
	EVT_MENU(IDM_RENDER_SETSOLUTIONFORMULA,wxMainWindow::OnMenuRenderSolutionSettings)
	EVT_MENU(IDM_RENDER_WIREFRAME,wxMainWindow::OnMenuRenderDraw)
	EVT_MENU(IDM_RENDER_SHADED,wxMainWindow::OnMenuRenderDraw)
	EVT_MENU(IDM_RENDER_CONTOURLINES,wxMainWindow::OnMenuRenderDraw)
	//EVT_MENU(IDM_RDRAW_FLOODED,wxMainWindow::OnMenuRenderDraw)
	EVT_MENU(IDM_RENDER_TRIM,wxMainWindow::OnMenuRenderDraw)
	EVT_MENU(IDM_RENDER_GRID,wxMainWindow::OnMenuRenderDraw)
	EVT_MENU(IDM_RENDER_RASTR,wxMainWindow::OnMenuRenderDraw)
	EVT_MENU(IDM_RENDER_RAYS,wxMainWindow::OnMenuRenderDraw)
	EVT_MENU(IDM_RENDER_SETSECTION,wxMainWindow::OnMenuRenderCutPlaneParams)
	EVT_MENU(IDM_RENDER_DUMPSCREEN,wxMainWindow::OnMenuRenderDumpScreen)
	EVT_MENU(IDM_HELP_ABOUT,wxMainWindow::OnMenuHelpAbout)
	EVT_IDLE(wxMainWindow::OnIdle)
	EVT_CLOSE(wxMainWindow::OnCloseWindow)
	//EVT_SIZE(wxMainWindow::OnResize)
END_EVENT_TABLE()


wxMainWindow::wxMainWindow(const int posX,const int posY,
						   const int width,const int height,
						   const wxChar* title)
: /*mfvWindow()
,*/ wxFrame((wxFrame *)NULL, wxID_ANY, wxString(title))
, m_pVMngr(&ViewManagerInst())
, m_pMCtrl(&ModelCtrlInst())
, m_status(NULL)
, m_searchTool(NULL)
, m_ptrGL(NULL)
#ifndef _USE_FV_LIB
,m_fhistory(NULL)
#endif
{
	logd("Constructor wxMainWindow\n");
	mfp_debug("wxMainWindow: Ctr\n");
	// Create statusbar & specify its properties
	int widths[] = { -1, 100,100, 100, 100 };
	m_status = CreateStatusBar();
	wxASSERT( m_status!=NULL );
	m_status->SetFieldsCount( WXSIZEOF(widths), widths );

	// Set icon
	SetIcon( wxICON( variable ) );

	#ifndef _USE_FV_LIB
	// Read configs
	wxConfigBase * pConfig = wxConfigBase::Get();
	pConfig->SetPath( wxT("FileHistory") );
	m_fhistory = new ::wxFileHistory();
	m_fhistory->Load( *pConfig );
	#endif

   	// Menu File
	wxMenu * filemenu = new wxMenu;
	#ifndef _USE_FV_LIB
	filemenu->Append(IDM_FILE_OPENMESH,wxT("Open &mesh file...\tCtrl+M"));
	filemenu->Append(IDM_FILE_OPENFIELD,wxT("Open &field file...\tCtrl+F"));
	filemenu->AppendSeparator();
	#endif
	filemenu->Append(IDM_FILE_REFRESH,wxT("Refresh field data"));
	filemenu->Append(IDM_FILE_RELOAD, wxT("Reload mesh and field data"));
	filemenu->Append(IDM_FILE_CLEAR,wxT("&Reset model"));
	#ifndef _USE_FV_LIB
	filemenu->AppendSeparator();
	m_fhistory->AddFilesToMenu(filemenu);
	#endif
	filemenu->AppendSeparator();
	filemenu->Append(IDM_FILE_EXIT,wxT("&Quit"));

	/// Menu View
	wxMenu* viewmenu = new wxMenu;
	viewmenu->AppendRadioItem(IDM_VIEW_PERSPECTIVE,wxT("Perspective"));
	viewmenu->AppendRadioItem(IDM_VIEW_ORTOGRAPHIC,wxT("Parallel"));
	viewmenu->AppendSeparator();
	viewmenu->AppendRadioItem(IDM_VIEW_TOP,wxT("&Top"));
	viewmenu->AppendRadioItem(IDM_VIEW_BOTTOM,wxT("Botto&m"));
	viewmenu->AppendRadioItem(IDM_VIEW_FRONT,wxT("&Front"));
	viewmenu->AppendRadioItem(IDM_VIEW_BACK,wxT("&Back"));
	viewmenu->AppendRadioItem(IDM_VIEW_LEFT,wxT("&Left"));
	viewmenu->AppendRadioItem(IDM_VIEW_RIGHT,wxT("Rig&ht"));
	viewmenu->AppendRadioItem(IDM_VIEW_DEFAULT,wxT("Defa&ult"));
	viewmenu->AppendSeparator();
	viewmenu->AppendRadioItem(IDM_VIEW_FULL,wxT("Full mode"));
	viewmenu->AppendRadioItem(IDM_VIEW_BOUNDINGBOX,wxT("Bounding box mode"));
	viewmenu->AppendRadioItem(IDM_VIEW_FAST,wxT("Fast mode"));
	viewmenu->AppendSeparator();
	viewmenu->Append(IDM_VIEW_NEWVIEW,wxT("New add"));
	viewmenu->Append(IDM_VIEW_NEXTVIEW,wxT("Next"));
	viewmenu->Append(IDM_VIEW_PREVIOUSVIEW,wxT("Previous"));
	viewmenu->AppendSeparator();
	viewmenu->Append(IDM_VIEW_DUMPCURRENTVIEW,wxT("Dump current"));
	viewmenu->Append(IDM_VIEW_DUMPALLVIEWS,wxT("Dump all"));

	// Menu Configuration
	wxMenu* cfgmenu = new wxMenu;
	cfgmenu->Append(IDM_CONFIGURE_AXES,wxT("Axes"),wxT("Displaying axexs"),true);
	cfgmenu->Append(IDM_CONFIGURE_GRID,wxT("Grid"),wxT("Displaying grid"), true);
	cfgmenu->Append(IDM_CONFIGURE_BACKGROUNDCOLOR,wxT("Background color"));
	cfgmenu->Append(IDM_CONFIGURE_LIGHT,wxT("Lighting"));
	cfgmenu->AppendSeparator();
	cfgmenu->Append(IDM_CONFIGURE_RESET,wxT("Defaults"));
	cfgmenu->Append(IDM_CONFIGURE_SAVECONFIGURATION,wxT("Save"));
	cfgmenu->AppendSeparator();
	cfgmenu->Append(IDM_CONFIGURE_EDITLEGEND,wxT("Edit legend..."));
	cfgmenu->AppendSeparator();
	cfgmenu->Append(IDM_CONFIGURE_CHANGEAPROXIMATIONMODULE,wxT("Use external approximation..."));

	/// Menu Render
	wxMenu* rendermenu = new wxMenu;
	rendermenu->Append(IDM_RENDER_SETSOLUTIONFORMULA,wxT("Solution settings..."));
	rendermenu->AppendSeparator();
	rendermenu->Append(IDM_RENDER_WIREFRAME,wxT("Draw element edges"),wxT("Turn On/Off edges of a mesh on the screen"),true);
	rendermenu->Append(IDM_RENDER_SHADED,wxT("Draw field"),wxT("Turn On/Off a solid solution on the screen"), true);
	rendermenu->Append(IDM_RENDER_CONTOURLINES,wxT("Draw contours"),wxT("Turn On/Off displaying of contours"), true);
	//rendermenu->Append(IDM_RDRAW_FLOODED,wxT("Draw colored contours"),wxT("Turn On/Off displaying of colored contours"), true);
	rendermenu->AppendSeparator();
	rendermenu->Append(IDM_RENDER_TRIM, wxT("Show cutted"),wxT("Turn On/Off slice of a model"), true);
	rendermenu->Append(IDM_RENDER_SETSECTION, wxT("Cut plane settings..."),wxT("Enter to cutting settings"));
	rendermenu->AppendSeparator();
	rendermenu->Append(IDM_RENDER_GRID, wxT("Draw grid"), wxT("Show grid acceleration structure"), true);
	rendermenu->AppendSeparator();
	rendermenu->AppendRadioItem(IDM_RENDER_RASTR, wxT("Use rasterization"), wxT("Switch to OpenGL rasterization"));
	rendermenu->AppendRadioItem(IDM_RENDER_RAYS, wxT("Use tracing rays"), wxT("Switch to Ray Tracing"));
	rendermenu->AppendSeparator();
	rendermenu->Append(IDM_RENDER_DUMPSCREEN,wxT("Save screen..."));
	rendermenu->AppendSeparator();

	// Menu Help
	wxMenu* helpmenu = new wxMenu;
	helpmenu->Append(IDM_HELP_ABOUT,wxT("&About..."));

	// Set menu toolbar
	wxMenuBar* menubar = new wxMenuBar(wxMB_DOCKABLE);
	SetMenuBar(menubar);

	menubar->Append(filemenu,	wxT("&File"));
	menubar->Append(viewmenu,	wxT("&View"));
	menubar->Append(cfgmenu, 	wxT("&Configuration"));
	menubar->Append(rendermenu, wxT("&Render"));
	menubar->Append(helpmenu, 	wxT("&Help"));

	menubar->Check(IDM_CONFIGURE_AXES, true);
	menubar->Check(IDM_CONFIGURE_GRID, true);
	menubar->Check(IDM_RENDER_WIREFRAME,    m_pVMngr->GetSettings()->bEdgeOn);
	menubar->Check(IDM_RENDER_SHADED, 	  m_pVMngr->GetSettings()->bShadingOn);
	menubar->Check(IDM_RENDER_CONTOURLINES,    m_pVMngr->GetSettings()->bIsovalueLineOn);
	//menubar->Check(IDM_RDRAW_FLOODED, ViewManagerInst()GetSettings()->bLineCoolored);
	menubar->Check(IDM_RENDER_TRIM,	  m_pVMngr->GetSettings()->bSliceModel);
	menubar->Check(IDM_RENDER_GRID,   m_pVMngr->GetSettings()->bIsGridDraw);
	menubar->Check(IDM_RENDER_RAYS, m_pVMngr->GetSettings()->bIsRayTracing);

	// Create toolbar
	//CreateWndToolBar();

	// Resize window to required sizes
	SetClientSize( wxSize(width,height) );
	SetPosition  ( wxPoint(posX,posY) );

	// Show this window
	this->Show(true);

	// OpenGL params
	#ifdef __WXMSW__
        int *gl_attrib = NULL;
    #else
    int gl_attrib[20] = { WX_GL_RGBA, WX_GL_MIN_RED, 1, WX_GL_MIN_GREEN, 1,
            WX_GL_MIN_BLUE, 1, WX_GL_DEPTH_SIZE, 1,
            WX_GL_DOUBLEBUFFER,
    #  if defined(__WXMAC__) || defined(__WXCOCOA__)
            GL_NONE };
    #  else
            None };
    #  endif
    #endif

	m_ptrGL = new wxRenderCanvas(m_pMCtrl,m_pVMngr, this, wxID_ANY, gl_attrib, GetPosition(),
		GetClientSize(),wxDEFAULT_FRAME_STYLE );
	if( !m_ptrGL) throw(fv_exception("Can't initialize OpenGL machine!") );
	m_pVMngr->Init(width,height);

	FV_CHECK_ERROR_GL();
	m_status->SetStatusText( wxT("OpenGL server alive"), 0 );
}

wxMainWindow::~wxMainWindow()
{
	logd("Destructor: wxMainWindow\n");


	// Destroy OpenGL machine
	wxDELETE( m_ptrGL );

    if( m_searchTool && !m_searchTool->GetToolBar() )
    {
        GetToolBar()->AddTool(m_searchTool);
    }

    #ifndef _USE_FV_LIB
	wxConfigBase * pConfig = wxConfigBase::Get();
	if( pConfig != NULL )
	{
		// TDO: write configs
		m_fhistory->Save(*pConfig);
		wxDELETE(m_fhistory)
	}
	#endif

	wxDELETE( m_status );
	//wxWindow::Destroy();
}

void wxMainWindow::DoInit(int cmd)
{
	logd("In wxMainWindow::DoIni\n");
	mfp_debug("wxMainWindow: DoInit\n");
	#ifndef _USE_FV_LIB
	wxCommandEvent event;
	OnMenuConfigModuleApprox(event);
	#else
	try {
		// First, read mesh data
		int nno(0), ned(0), nfa(0), nel(0);
		m_pMCtrl->Do((ModelCtrl::eCommnad)cmd);
		FV_CHECK_ERROR_GL();
		if (m_pMCtrl->GetCurrentMesh()) {
			nno = m_pMCtrl->GetCurrentMesh()->GetNumNodes();
			ned = m_pMCtrl->GetCurrentMesh()->GetNumEdges();
			nfa = m_pMCtrl->GetCurrentMesh()->GetNumFaces();
			nel = m_pMCtrl->GetCurrentMesh()->GetNumElems();
		}
		m_status->SetStatusText( wxString::Format(wxT("no: %d"), nno), 1);
		m_status->SetStatusText( wxString::Format(wxT("ed: %d"), ned), 2);
		m_status->SetStatusText( wxString::Format(wxT("fa: %d"), nfa), 3);
		m_status->SetStatusText( wxString::Format(wxT("el: %d"), nel), 4);

	} catch(fv_exception& ex) {
		std::cout << ex << std::endl;
	} catch(...)
	{
		std::cout<< "Something is wrong!\n";
	}
	#endif
}

//void wxMainWindow::RefreshScreen(void) 
//{
//	wxASSERT( m_ptrGL!=NULL );
//	m_ptrGL->wxWindow::Refresh(false);
//}

///----Private methods --------------------------------------------
void wxMainWindow::OnChar(wxKeyEvent& event)
{
    #if wxUSE_UNICODE
    int key = event.GetUnicodeKey();
    #else
    int key = event.GetKeyCode();
    #endif

    switch( key )
    {
        case WXK_ESCAPE:
            wxTheApp->ExitMainLoop();
            return;

        default:
			//getViewManager().KeyboardCallback(
            event.Skip();
            return;
    }

    this->Refresh(false);
}


// Menu
#ifndef _USE_FV_LIB
void wxMainWindow::OnMenuFileOpen(wxCommandEvent& event)
{
	wxMessageDialog *dlg(NULL);
	wxString s_extdef, wxErrMsg;
	wxString title(_T("Open "));
	title += (event.GetId() == IDM_OPEN_MESH) ? wxString(_T("mesh file")) : wxString(_T("field file"));
	wxString wxPath = wxFileSelector(title,
								   wxEmptyString,
								   wxEmptyString,
								   wxString::Format
			                       (
			                    		   _T("Input file (*.dat;*dmp)|*.dat;*.dmp|All files (%s)|%s"),
			                               wxFileSelectorDefaultWildcardStr,
			                               wxFileSelectorDefaultWildcardStr
			                       ),
			                       wxFileSelectorDefaultWildcardStr,
			                       wxCHANGE_DIR,
			                       this);
	if (!wxPath)   return;
	else
    {
		try
		{
			#ifndef __WXDEBUG__
			wxBusyInfo infoRead(_T("Reading file, please wait..."), this);
			#endif
			//_proj.Init(path.mb_str(), file_type);
			_fhistory->AddFileToHistory(wxPath);
			_fhistory->AddFilesToMenu();
			m_ptrGL->Refresh(true);
		}
		catch (fv_exception& ex)
		{
			std::ostringstream oss;
			oss << ex;
			wxString reson;
			reson.Printf(_T("%s"),oss.str() );
			(void)wxMessageBox(reson,_T("Error"),wxICON_ERROR | wxOK);

		}
	}

	try 
	{
		//GetFilePath(wxPath,event.GetId());

	}
	catch(std::runtime_error & Ex)
	{
		wxErrMsg.Printf(_T("%s"), Ex.what());
		dlg = new wxMessageDialog(NULL, wxErrMsg, _T("Error"), wxOK | wxICON_ERROR);
	}
	catch(...)
	{
		wxErrMsg = _T("Error accrued while loading file ");
		wxErrMsg.append(wxPath);
		dlg = new wxMessageDialog(NULL, wxErrMsg, _T("Error"), wxOK | wxICON_ERROR);
    }

	if(dlg) {
		dlg->ShowModal();
		dlg->Destroy();
	}
	
}
#endif

void wxMainWindow::OnMenuFileReset(wxCommandEvent& WXUNUSED(event))
{
	DoInit(ModelCtrl::CLEAR);

		wxFrame::SetTitle(wxT("FemViewer"));
		m_status->SetStatusText(wxT("Reaet done... "),0);
		m_status->SetStatusText(wxT("no: "),1);
		m_status->SetStatusText(wxT("ed: "),2);
		m_status->SetStatusText(wxT("fa: "),3);
		m_status->SetStatusText(wxT("el: "),4);
		m_ptrGL->Refresh(true);

}

/*void wxMainWindow::OnMenuFileDump(wxCommandEvent& WXUNUSED(event))
{
	if(m_pVMngr->MenuCallback("general_dump_characteristics")){
		m_ptrGL->Refresh(false);
	}
}*/



void wxMainWindow::OnMenuFileHistory(wxCommandEvent& event)
{
//	const int idFile = event.GetId() - wxID_FILE;
//	if(idFile < MAX_HISTORY_FILES)
//	{
//		wxString wxPath = _fhistory->GetHistoryFile(idFile);
//		_proj.setFileName(wxPath.mb_str());
//	} else {
//		event.Skip();
//	}

	m_ptrGL->Refresh(false);
}


// This function refresh field data
void wxMainWindow::OnMenuFileRefresh(wxCommandEvent& WXUNUSED(event))
{
	//m_pVMngr->MenuCallback(IDM_FILE_REFRESH);
	this->DoInit(ModelCtrl::REFRESH);
	m_ptrGL->Refresh(false);
}

void wxMainWindow::OnMenuFileReload(wxCommandEvent& WXUNUSED(event))
{
	//m_pVMngr->MenuCallback(IDM_FILE_REFRESH);
	this->DoInit(ModelCtrl::RELOAD);
	m_ptrGL->Refresh(false);
}

void wxMainWindow::OnMenuFileQuit(wxCommandEvent& WXUNUSED(event))
{
	logd("wxMainWindow: Quiting!\n");
	m_pMCtrl->Clear();
	m_ptrGL->CleanUp();
	Close(true);
}

void wxMainWindow::OnMenuViewProjection(wxCommandEvent& event)
{
	if(event.GetId() == IDM_VIEW_PERSPECTIVE)
		m_pVMngr->MenuCallback(IDM_VIEW_PERSPECTIVE);
	else if(event.GetId() == IDM_VIEW_ORTOGRAPHIC)
		m_pVMngr->MenuCallback(IDM_VIEW_ORTOGRAPHIC);
	m_ptrGL->Refresh(false);

}

void wxMainWindow::OnMenuChangeView(wxCommandEvent& event)
{
	int evt_id = event.GetId();
	switch(evt_id)
	{
	case IDM_VIEW_TOP:
	case IDM_VIEW_BOTTOM:
	case IDM_VIEW_FRONT:
	case IDM_VIEW_BACK:
	case IDM_VIEW_LEFT:
	case IDM_VIEW_RIGHT:
	case IDM_VIEW_DEFAULT:
	case IDM_VIEW_FULL:
	case IDM_VIEW_FAST:
		if(m_pVMngr->MenuCallback(evt_id))
				m_ptrGL->Refresh(false);
		break;
	

	default:
		break;
	}

}

void wxMainWindow::OnMenuViewMode(wxCommandEvent& event)
{
	const int evt_id = event.GetId();
	switch(evt_id)
	{
	case IDM_VIEW_FULL:
	case IDM_VIEW_BOUNDINGBOX:
	case IDM_VIEW_FAST:
		if(m_pVMngr->MenuCallback(evt_id))
				m_ptrGL->Refresh(false);
		return;
	default:
		return;
	}

}

void wxMainWindow::OnMenuViewNew(wxCommandEvent& event)
{
	if(m_pVMngr->MenuCallback(IDM_VIEW_NEWVIEW)) {
		m_ptrGL->Refresh(false);
	}
}

void wxMainWindow::OnMenuViewNext(wxCommandEvent& event)
{
	if(m_pVMngr->MenuCallback(IDM_VIEW_NEXTVIEW)) {
		m_ptrGL->Refresh(false);
	}
}

void wxMainWindow::OnMenuViewPrevious(wxCommandEvent& event)
{
	if(m_pVMngr->MenuCallback(IDM_VIEW_PREVIOUSVIEW)) {
		m_ptrGL->Refresh(false);
	}
}

void wxMainWindow::OnMenuViewDumpCurr(wxCommandEvent& event)
{
	if(m_pVMngr->MenuCallback(IDM_VIEW_DUMPCURRENTVIEW)) {
		m_ptrGL->Refresh(false);
	}
}

void wxMainWindow::OnMenuViewDumpAll(wxCommandEvent& event)
{
	if(m_pVMngr->MenuCallback(IDM_VIEW_DUMPALLVIEWS)) {
		m_ptrGL->Refresh(false);
	}
}

void wxMainWindow::OnMenuConfigAxes(wxCommandEvent& event)
{
	if(m_pVMngr->MenuCallback(IDM_CONFIGURE_AXES)) {
		m_ptrGL->Refresh(false);
	}
}

void wxMainWindow::OnMenuConfigGrid(wxCommandEvent& event)
{
	if(m_pVMngr->MenuCallback(IDM_CONFIGURE_GRID)) {
		m_ptrGL->Refresh(false);
	}
}

void wxMainWindow::OnMenuConfigBkgColor(wxCommandEvent& event)
{
	if(m_pVMngr->MenuCallback(IDM_CONFIGURE_BACKGROUNDCOLOR)) {
		m_ptrGL->Refresh(true);
	}
}

void wxMainWindow::OnMenuConfigLight(wxCommandEvent& event)
{
	if(m_pVMngr->MenuCallback(IDM_CONFIGURE_LIGHT)) {
		m_ptrGL->Refresh(false);
	}
}

void wxMainWindow::OnMenuConfigReset(wxCommandEvent& event)
{
	if(m_pVMngr->MenuCallback(IDM_VIEW_DEFAULT)) {
		m_ptrGL->Refresh(false);
	}
}

void wxMainWindow::OnMenuConfigSave(wxCommandEvent& event)
{
	if(m_pVMngr->MenuCallback(IDM_CONFIGURE_SAVECONFIGURATION)) {
		m_ptrGL->Refresh(true);
	}
}

void wxMainWindow::OnMenuConfigLegendEdit(wxCommandEvent& event)
{
	// Temporary store current legend configuration
	Legend alegend(m_pVMngr->GetLegend());
	wxLegendDialog *dlg = new wxLegendDialog(wxString(wxT("Edit legend")),alegend);

    if (dlg->ShowModal() == wxID_OK) {
    	// Now model points to changed legend
    	//m_pMCtrl->GetLegend() = alegend;
    	m_pMCtrl->Do(ModelCtrl::LEGCHANGE);
    }
    dlg->Destroy();
	m_ptrGL->Refresh(false);
}

void wxMainWindow::OnMenuConfigModuleApprox(wxCommandEvent & WXUNUSED(event))
{
//	mod_approx& mod = m_Project.GetModuleType();
//	wxApproxModWnd* dlg = new wxApproxModWnd(this,mod);
//	dlg->CenterOnParent();
//	if(wxID_OK == dlg->ShowModal())
//	{
//		m_Project.set_module();
//	}
//
//	dlg->Destroy();
	m_ptrGL->Refresh(false);
}

void wxMainWindow::OnMenuRenderSolutionSettings(wxCommandEvent& WXUNUSED(event))
{
	SolutionData lcurrSol( m_pMCtrl->GetCurrentField()->GetSolution() );
	//int nr_sols = lcurSolModelCtrlInst()->GetCurrentField()->GetNrSol();
	//int nr_equs = ModelCtrlInst()->GetCurrentField()->GetNreq();
	//int cur_sol = ModelCtrlInst()->GetCurrentField()->GetCurrSol();
	//const std::string& formula = ModelCtrlInst()->GetCurrentField()->GetFromula();

	//wxSolCalcDialog* dlg = new wxSolCalcDialog(nr_equs,nr_sols,cur_sol,formula);
	wxSolCalcDialog* dlg = new wxSolCalcDialog(lcurrSol.nrEquetions,lcurrSol.nrSolutions,lcurrSol.currSolution,lcurrSol.sFormula);
	if(dlg->ShowModal() == wxID_OK)
	{
		lcurrSol.currSolution = dlg->GetCurrSol();
		lcurrSol.sFormula     = dlg->GetFunction();
		if (m_pMCtrl->CurrentSolution = lcurrSol) {
			logd("Solution Changed\n");
			//ModelCtrlInst()->GetCurrentField()->GetCurrSol() = dlg->GetCurrSol();
			//ModelCtrlInst()->GetCurrentField()->GetFromula() = dlg->GetFunction();

			#ifndef __WXDEBUG__
			wxBusyInfo infoCalc(_T("Calculation, please wait..."), this);
			#endif
			this->DoInit(ModelCtrl::REFRESH);
			m_ptrGL->Refresh(true);
		}
	}

	dlg->Destroy();
}


void wxMainWindow::OnMenuRenderDraw(wxCommandEvent & event)
{
	const bool check = event.IsChecked() ? true : false;
	const unsigned int key(event.GetId());

	switch(key)
	{
		case IDM_RENDER_WIREFRAME: // Draw mesh edges
			m_pVMngr->GetSettings()->bEdgeOn = check;
			break;
		case IDM_RENDER_SHADED: // Draw field
			m_pVMngr->GetSettings()->bShadingOn = check;
			break;
		case IDM_RENDER_CONTOURLINES: // Draw contours
			m_pVMngr->GetSettings()->bIsovalueLineOn = check;
			break;
		//case IDM_RDRAW_FLOODED: // Draw colored contours
		//	ViewManagerInst()GetSettings()->bLineCoolored = check;
		//	return;
		case IDM_RENDER_TRIM: // Draw cutted
			m_pVMngr->GetSettings()->bSliceModel = check;
			return;
		case IDM_RENDER_GRID:
			m_pVMngr->GetSettings()->bIsGridDraw = check;
			break;
		case IDM_RENDER_RASTR:
		case IDM_RENDER_RAYS:
			m_pVMngr->GetSettings()->bIsRayTracing = check;
			break;
		default:
			return;
	}
	
	m_pMCtrl->Do(ModelCtrl::UPDATE);
	m_ptrGL->Refresh(true);

}



void wxMainWindow::OnMenuRenderDumpScreen(wxCommandEvent &event)
{
	wxFileDialog dialog(this,
		_T("Specyfy a file name to save"),
		wxEmptyString,
		_T("screen.png"),
        _T("PNG files (*.png)|*.png|All files (*.*)|*.*"),
		wxFD_SAVE|wxFD_OVERWRITE_PROMPT);
	dialog.SetFilterIndex(0);
	if (dialog.ShowModal() == wxID_OK)
    {
        //wxLogMessage(_T("%s, filter %d"),
          //           dialog.GetPath().c_str(), dialog.GetFilterIndex());
		ScreenShot( dialog.GetPath());
    }
	m_pVMngr->AddStatusMsg("Saving screen");
	m_ptrGL->Refresh(true);

}

void wxMainWindow::OnMenuRenderSettings(wxCommandEvent &event)
{
	wxScreenSetts dlg(ViewManagerInst(), this);
    dlg.ShowModal();
}

void wxMainWindow::OnMenuRenderCutPlaneParams(wxCommandEvent& event)
{
	//bool result = false;

	const double * p = m_pMCtrl->GetCutPlane().GetParams();
	wxPlaneCutDialog dlg(wxT("Cut plane parameters"),p[0], p[1], p[2], p[3]);

    if ( dlg.ShowModal() == wxID_OK ) 
	{
    
		if( dlg._A != p[0] || 
			dlg._B != p[1] || 
			dlg._C != p[2] ||
			dlg._D != p[3] ) 
		{
			m_pMCtrl->GetCutPlane().Set(dlg._A,dlg._B,dlg._C,dlg._D);
			m_pMCtrl->Do(ModelCtrl::CUTPLANECHANGE);
			m_ptrGL->Refresh(true);
		}   
		
	}
}


void wxMainWindow::OnMenuHelpAbout(wxCommandEvent& WXUNUSED(event))
{
	wxMessageBox(wxT("Paweł Macioł - Finite Element Viewer"));
}

void wxMainWindow::OnToolLeftClick(wxCommandEvent & event)
{
	//static const char * cmds[] = {"x_dof","y_dof","z_dof","f_dof"};
	int cmd = 0;
	//const int id = event.GetId();
	if (event.GetId() == IDT_XDOF)
	{
		cmd = IDM_VIEW_RIGHT;
	} else if (event.GetId() == IDT_YDOF)
	{
		cmd = IDM_VIEW_TOP;
	} else if (event.GetId() == IDT_ZDOF)
	{
		cmd = IDM_VIEW_FRONT;
	} else if (event.GetId() == IDT_FDOF)
	{
		cmd = IDM_VIEW_DEFAULT;
	} else {
		event.Skip();
		return;
	}

	m_pVMngr->MenuCallback(cmd);
	
}


void wxMainWindow::ScreenShot(const wxString& path)
{
	int w, h;
	m_ptrGL->GetClientSize(&w, &h);

	const size_t imgDepth = 3;
	const size_t imgSize = imgDepth * size_t(w) * size_t(h);

	typedef unsigned char byte;

	byte* pixbuf = static_cast<byte*>(malloc(imgSize));

	int tl_x, tl_y;

	//m_ptrGL->DoGetPosition(&tl_x, &tl_y);
	m_ptrGL->GetPosition(&tl_x, &tl_y);

	const int bl_y = GetClientSize().GetHeight() - (tl_y + h);

	glPixelStorei(GL_PACK_ALIGNMENT, 1);
	glReadPixels(tl_x, bl_y, w, h, GL_RGB, GL_UNSIGNED_BYTE, pixbuf);

	for(int y = 0; y < h / 2; y++)
	{
		const int swapY = h - y - 1;
		for(int x = 0; x < w; x++)
		{
			const int offset = int(imgDepth) * (x + y * w);
			const int swapOffset = int(imgDepth) * (x + swapY * w);

			// Swap R, G and B of the 2 pixels
			std::swap(pixbuf[offset + 0], pixbuf[swapOffset + 0]);
			std::swap(pixbuf[offset + 1], pixbuf[swapOffset + 1]);
			std::swap(pixbuf[offset + 2], pixbuf[swapOffset + 2]);
		}
	}

	wxImage img(w, h, pixbuf);
	img.SaveFile(path,wxBITMAP_TYPE_PNG );

	//if(pixbuf) free(pixbuf);

}

void wxMainWindow::OnIdle(wxIdleEvent &event)
{
    if (this->m_shutdown) Close();
    m_pVMngr->DisplayCallback();
}

void wxMainWindow::OnCloseWindow(wxCloseEvent& event)
{
	if (event.CanVeto()) {
		this->m_ptrGL->CleanUp();
	}
	this->Destroy();
}

//void wxMainWindow::OnResizeWindow(wxSizeEvent& event)
//{
//	ViewManagerInst()ReshapeCallback();
//}
/*
wxImage wxMainWindow::DumpImage()
{
	const RenderingOptions& renderingOptions = m_appData.GetRenderingOptions();

	const int width = renderingOptions.OutputWidth();
	const int height = renderingOptions.OutputHeight();
	
	const size_t bytesPerPixel = 3;	// RGB
	const size_t imageSizeInBytes = bytesPerPixel * size_t(width) * size_t(height);
	
	// Allocate with malloc, because the data will be managed by wxImage
	BYTE* pixels = static_cast<BYTE*>(malloc(imageSizeInBytes));

	// glReadPixels takes the lower-left corner, while GetViewportOffset gets the top left corner
	const wxPoint topLeft = GetViewportOffset();
	const wxPoint lowerLeft(topLeft.x, GetClientSize().GetHeight() - (topLeft.y + height));

	// glReadPixels can align the first pixel in each row at 1-, 2-, 4- and 8-byte boundaries. We
	// have allocated the exact size needed for the image so we have to use 1-byte alignment
	// (otherwise glReadPixels would write out of bounds)
	glPixelStorei(GL_PACK_ALIGNMENT, 1);
	glReadPixels(lowerLeft.x, topLeft.y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);

	// glReadPixels reads the given rectangle from bottom-left to top-right, so we must
	// reverse it
	for(int y = 0; y < height / 2; y++)
	{
		const int swapY = height - y - 1;
		for(int x = 0; x < width; x++)
		{
			const int offset = int(bytesPerPixel) * (x + y * width);
			const int swapOffset = int(bytesPerPixel) * (x + swapY * width);

			// Swap R, G and B of the 2 pixels
			std::swap(pixels[offset + 0], pixels[swapOffset + 0]);
			std::swap(pixels[offset + 1], pixels[swapOffset + 1]);
			std::swap(pixels[offset + 2], pixels[swapOffset + 2]);
		}
	}
	
	return wxImage(width, height, pixels);
}
*/

void wxMainWindow::CreateWndToolBar()
{
    // Delete and recreate the toolbar
    wxToolBarBase *toolBar = GetToolBar();
    long style = toolBar ? toolBar->GetWindowStyle() : TOOLBAR_STYLE;

    if (toolBar && m_searchTool && m_searchTool->GetToolBar() == NULL)
    {
        // see ~wxMainWindow()
        toolBar->AddTool(m_searchTool);
    }

    m_searchTool = NULL;

    delete toolBar;

    SetToolBar(NULL);

    style &= ~(wxTB_HORIZONTAL | wxTB_VERTICAL | wxTB_BOTTOM | wxTB_RIGHT | wxTB_HORZ_LAYOUT);
	// On top
	style |= wxTB_TOP;
	// With tips
    style &= ~wxTB_NO_TOOLTIPS;

    if ( (style & wxTB_TEXT) && !(style & wxTB_NOICONS))
        style |= wxTB_HORZ_LAYOUT;

    toolBar = CreateToolBar(style, ID_TOOLBAR);

    PopulateToolbar(toolBar);

}


enum {
	IDT_XDOF, IDT_YDOF, IDT_ZDOF, IDT_FREEDOF
};

void wxMainWindow::PopulateToolbar(wxToolBarBase* toolBar)
{
    // Set up toolbar
    enum {
        Tool_xaxis,
        Tool_yaxis,
		Tool_zaxis,
		#ifdef __WXMSW__
        Tool_faxis,
		#else
        Tool_free,
		#endif
        Tool_Max
    };

	// Declare table of toolbar bitmaps
    wxBitmap toolBarBitmaps[Tool_Max];

	#if USE_XPM_BITMAPS
    	#define INIT_TOOL_BMP(bmp) \
        toolBarBitmaps[Tool_##bmp] = wxBitmap(bmp##_xpm)
	#else // !USE_XPM_BITMAPS
    	#define INIT_TOOL_BMP(bmp) \
        toolBarBitmaps[Tool_##bmp] = wxBITMAP(bmp)
	#endif // USE_XPM_BITMAPS/!USE_XPM_BITMAPS

    INIT_TOOL_BMP(xaxis);
    INIT_TOOL_BMP(yaxis);
    INIT_TOOL_BMP(zaxis);
	#ifdef __WXMSW__
    INIT_TOOL_BMP(faxis);
	#else
    INIT_TOOL_BMP(free);
	#endif

    int w = toolBarBitmaps[Tool_xaxis].GetWidth(),
        h = toolBarBitmaps[Tool_xaxis].GetHeight();


    // this call is actually unnecessary as the toolbar will adjust its tools
    // size to fit the biggest icon used anyhow but it doesn't hurt neither
    toolBar->SetToolBitmapSize(wxSize(w, h));

	#ifdef __WXMSW__
	int width = 24;
	#else
	int width = 16;
	#endif
	int currentX = 5;

	toolBar->AddTool(IDT_XDOF, toolBarBitmaps[0], wxNullBitmap, false, currentX, -1, (wxObject *) NULL, wxT("X dof"));
	currentX += width + 5;
	toolBar->AddTool(IDT_YDOF, toolBarBitmaps[1], wxNullBitmap, false, currentX, -1, (wxObject *) NULL, wxT("Y dof"));
	currentX += width + 5;
	toolBar->AddTool(IDT_ZDOF, toolBarBitmaps[2], wxNullBitmap, false, currentX, -1, (wxObject *) NULL, wxT("Z dof"));
	currentX += width + 5;
	toolBar->AddTool(IDT_FREEDOF, toolBarBitmaps[3], wxNullBitmap, false, currentX, -1, (wxObject *) NULL, wxT("Free dof"));
	currentX += width + 5;
	toolBar->AddSeparator();

   // This is needed!
    toolBar->Realize();
}

void wxMainWindow::SetTitle(const wxString& title)
{
	wxString tmpTile(wxT("FemViewer - "));
	tmpTile.append(wxString(m_pMCtrl->GetCurrentMesh()->Name().c_str(),wxConvUTF8));
	wxFrame::SetTitle(tmpTile);
}

}
}
